use std::future::{ready, Ready};

use actix_web::{dev::Payload, FromRequest, HttpRequest};

use crate::{
    error::{new_err, AppErr, ErrWrap},
    web::{
        cfg::{HTTP_DEVICE_SESSION_HEAD, HTTP_USER_SERSSION_HEAD},
        codec::device_session::get_device_session,
    },
};

use super::{
    device_session::SharedDeviceState,
    user_session::{get_user_session, UserSession},
};

pub enum Session {
    User(UserSession),
    Device(SharedDeviceState),
}

fn get_session(req: &HttpRequest) -> Result<Session, AppErr> {
    let device_token = req.headers().get(HTTP_DEVICE_SESSION_HEAD);
    if let Some(device_token) = device_token {
        let id: i64 = device_token.to_str().wrap()?.parse().wrap()?;
        let session = get_device_session(id)?;
        return Ok(Session::Device(session));
    } else {
        let id: i64 = req
            .headers()
            .get(HTTP_USER_SERSSION_HEAD)
            .ok_or(new_err("no use id"))?
            .to_str()
            .wrap()?
            .parse()
            .wrap()?;
        let session = get_user_session(id)?;
        return Ok(Session::User(session));
    }
}

impl FromRequest for Session {
    type Error = AppErr;
    type Future = Ready<Result<Self, AppErr>>;

    fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
        ready(get_session(req))
    }
}
